package com.xcm.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.xcm.config.CustomProperties;
import com.xcm.constant.BusinessConstant;
import com.xcm.constant.DateFormatConstant;
import com.xcm.constant.OperationLogConstant;
import com.xcm.constant.PageConstant;
import com.xcm.dao.ProgramJsonMapper;
import com.xcm.exception.ServiceException;
import com.xcm.export.entity.SingleProgramDetailReportData;
import com.xcm.model.*;
import com.xcm.model.dto.ProgramJsonListDTO;
import com.xcm.model.dto.SingleProgramDetailReportDTO;
import com.xcm.model.dto.WholeProgramReportDTO;
import com.xcm.model.vo.ProgramJsonStatVO;
import com.xcm.model.vo.SingleProgramDetailReportVO;
import com.xcm.model.vo.WholeProgramReportVO;
import com.xcm.page.PageInfo;
import com.xcm.service.*;
import com.xcm.util.DateUtils;
import com.xcm.util.DecodeUtils;
import com.xcm.util.FileUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.util.List;
import java.util.Set;

/**
 * 节目JsonService实现类
 */
@Service(value = "programJsonService")
public class ProgramJsonServiceImpl implements ProgramJsonService {
	@Autowired
	private ProgramJsonMapper programJsonMapper;
	@Autowired
	private ProgramTopService programTopService;
	@Autowired
	private ProgramBottomService programBottomService;
	@Autowired
	private ProgramInfoService programInfoService;
	@Autowired
	private OperationLogService operationLogService;
	@Autowired
	private CustomProperties customProperties;

	/**
	 * 发布节目
	 * publishProgram
	 *
	 * @param xcVersion 版本号
	 * @param url       Json文件下载地址
	 */
	@Override
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void publishProgram(String xcVersion, String url) throws UnsupportedEncodingException, ServiceException {
		String jsonFileSavePath = customProperties.getJsonFileSavePath();
		//验证json文件保存路径是否为空
		if (StringUtils.isBlank(jsonFileSavePath)) {
			throw new ServiceException("json文件保存路径为空");
		}
		//对Url进行解码
		url = DecodeUtils.decodeUnicode(url);
		//更加xc版本查询TbProgramJson
		TbProgramJson programJson = programJsonMapper.getProgramJsonByXcVersion(xcVersion);
		//数据已存在
		if (programJson != null) {
			return;
		}
		//保存节目Json
		programJson = new TbProgramJson();
		programJson.setXcVersion(xcVersion);
		programJson.setCmsVersion(String.valueOf(System.currentTimeMillis()));
		programJson.setReceiveTime(System.currentTimeMillis());
		programJson.setUrl(url);
		int lastindex = url.lastIndexOf("/");
		String name = url.substring(lastindex + 1);
		programJson.setName(name);
		programJson.setDownState(1);
		//saveProgramJson(programJson);
		//下载Json文件
		FileUtils.saveUrlAs(url, name, 3);
		//json文件存放目录
		String data = FileUtils.readFile(jsonFileSavePath + File.separator + name);
		if (StringUtils.isBlank(data)) {
			Integer downState = 2;
			//保存操作日志
			TbOperationLog operationLog = new TbOperationLog();
			operationLog.setOperationTypeId(OperationLogConstant.OPERATION_LOG_TYPE_PUBLISH);
			operationLog.setOperationContent(programJson.getName() + "发布失败,数据下载失败");
			operationLog.setIsSuccess(OperationLogConstant.OPERATION_LOG_SUCCESS);
			operationLog.setOperationTime(System.currentTimeMillis());
			// TODO: 2018/4/9 处理用户ID和IP地址
			//展示设置操作用户名、用户真实姓名、IP为空，用户保存在统一登录系统
			operationLog.setUserName("");
			operationLog.setRealName("");
			operationLog.setOperationIp("");
			operationLogService.saveOperationLog(operationLog);
			programJsonMapper.updateProgramJsonDownStateById(downState, programJson.getProgramJsonId());
			return;
		}
		programJson.setDeviceDownState(1);
		programJson.setDownState(0);
		programJson.setPath("jsons/" + name);
		//programJsonMapper.updateProgramJson(programJson);

		JSONObject jsonObject = null;
		try {
			jsonObject = JSON.parseObject(data);
			programJson.setJsonAuth(0);
		} catch (Exception e) {
			programJson.setJsonAuth(1);
			// TODO: 2018/4/10 日志处理
			//保存操作日志
			TbOperationLog operationLog = new TbOperationLog();
			operationLog.setOperationTypeId(OperationLogConstant.OPERATION_LOG_TYPE_PUBLISH);
			operationLog.setOperationContent(programJson.getName() + "发布失败,JSON验证失败");
			operationLog.setIsSuccess(OperationLogConstant.OPERATION_LOG_SUCCESS);
			operationLog.setOperationTime(System.currentTimeMillis());
			// TODO: 2018/4/9 处理用户ID和IP地址
			//展示设置操作用户名、用户真实姓名、IP为空，用户保存在统一登录系统
			operationLog.setUserName("");
			operationLog.setRealName("");
			operationLog.setOperationIp("");
			operationLogService.saveOperationLog(operationLog);
			return;
		}

		//上屏节目
		JSONObject topOrders = jsonObject.getJSONObject("topOrders");
		if (topOrders != null) {
			List<TbProgramTop> topList = Lists.newArrayList();
			Set<String> topSet = topOrders.keySet();
			for (String key : topSet) {
				TbProgramTop programTop = new TbProgramTop();
				programTop.setXcVersion(programJson.getXcVersion());
				programTop.setCmsVersion(programJson.getCmsVersion());
				programTop.setName(key);
				programTop.setUrl(String.valueOf(topOrders.get(key)));
				programTop.setAddTime(System.currentTimeMillis());
				topList.add(programTop);
			}
			programTopService.saveProgramTopBatch(topList);
		}

		//下屏节目
		JSONObject bottomOrders = jsonObject.getJSONObject("bottomOrders");
		if (bottomOrders != null) {
			List<TbProgramBottom> bottomList = Lists.newArrayList();
			Set<String> topSet = bottomOrders.keySet();
			for (String key : topSet) {
				TbProgramBottom programBottom = new TbProgramBottom();
				programBottom.setXcVersion(programJson.getXcVersion());
				programBottom.setCmsVersion(programJson.getCmsVersion());
				programBottom.setName(key);
				programBottom.setUrl(String.valueOf(bottomOrders.get(key)));
				programBottom.setAddTime(System.currentTimeMillis());
				bottomList.add(programBottom);
			}
			programBottomService.saveProgramBottomBatch(bottomList);
		}
		//节目信息
		JSONArray orders = jsonObject.getJSONArray("orders");
		if (orders != null) {
			//设置终端数，终端下载成功后才开始计数
			programJson.setDeviceNum(0);
			//programJsonMapper.updateProgramJson(programJson);
			List<TbProgramInfo> programInfoList = Lists.newArrayList();
			for (int i = 0; i < orders.size(); i++) {
				Object obj = orders.get(i);
				if (obj == null) {
					continue;
				}
				JSONObject orderObj = (JSONObject) obj;
				String top = orderObj.getJSONArray("top").toJSONString().replace("[", "").replace("]", "");
				String bottom = orderObj.getJSONArray("bottom").toJSONString().replace("[", "").replace("]", "");
				TbProgramInfo programInfo = new TbProgramInfo();
				programInfo.setXcVersion(programJson.getXcVersion());
				programInfo.setCmsVersion(programJson.getCmsVersion());
				programInfo.setMachineNum(String.valueOf(orderObj.get("machine_num")));
				programInfo.setTop(top);
				programInfo.setBottom(bottom);
				programInfo.setAddTime(System.currentTimeMillis());
				programInfoList.add(programInfo);
			}
			programInfoService.saveProgramTopBatch(programInfoList);
		}
		saveProgramJson(programJson);
		// TODO: 2018/4/10 处理日志
		//保存操作日志
		TbOperationLog operationLog = new TbOperationLog();
		operationLog.setOperationTypeId(OperationLogConstant.OPERATION_LOG_TYPE_PUBLISH);
		operationLog.setOperationContent(programJson.getName() + "发布成功");
		operationLog.setIsSuccess(OperationLogConstant.OPERATION_LOG_SUCCESS);
		operationLog.setOperationTime(System.currentTimeMillis());
		// TODO: 2018/4/9 处理用户ID和IP地址
		//展示设置操作用户名、用户真实姓名、IP为空，用户保存在统一登录系统
		operationLog.setUserName("");
		operationLog.setRealName("");
		operationLog.setOperationIp("");
		operationLogService.saveOperationLog(operationLog);
	}

	/**
	 * 保存节目Json
	 * saveProgramJson
	 *
	 * @param programJson TbProgramJson类型对象
	 */
	@Override
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void saveProgramJson(TbProgramJson programJson) {
		programJsonMapper.saveProgramJson(programJson);
	}

	/**
	 * 获取节目Json列表(分页)
	 * listProgramJsonByPage
	 *
	 * @param timeType        筛选时间类型称
	 * @param startTime       筛选时间-开始
	 * @param endTime         筛选时间-结束
	 * @param deviceDownState 终端下载状态
	 * @param checkType       校验状态
	 * @param publishId       发布Id
	 * @param pageNum         当前页
	 * @param pageSize        每页显示条数
	 * @return Page<ProgramJsonListDTO>
	 */
	@Override
	public Page<ProgramJsonListDTO> listProgramJsonByPage(String timeType, String startTime, String endTime, String deviceDownState, String checkType, Long publishId, Integer pageNum, Integer pageSize) {
		PageHelper.startPage(pageNum, pageSize);
		Long start = null;
		Long end = null;
		try {
			if (StringUtils.isNotBlank(startTime)) {
				start = DateUtils.stringTimeToLongTimeStamp(startTime, DateFormatConstant.LONG_DATE_FORMAT_STR);
			}
			if (StringUtils.isNotBlank(endTime)) {
				end = DateUtils.stringTimeToLongTimeStamp(endTime, DateFormatConstant.LONG_DATE_FORMAT_STR);
			}
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return programJsonMapper.listProgramJsonByPage(timeType, start, end, deviceDownState, checkType, publishId);
	}

	/**
	 * 通过xc版本获取节目Json
	 * getProgramJsonByXcVersion
	 *
	 * @param xcVersion xc版本号
	 * @return TbProgramJson
	 */
	@Override
	public TbProgramJson getProgramJsonByXcVersion(String xcVersion) {
		return programJsonMapper.getProgramJsonByXcVersion(xcVersion);
	}

	/**
	 * 获取终端下载广告成功数量（所有终端下载完毕该批次广告，成功数量+1,多一个终端对应一批广告，有一个失败即失败数+1）
	 *
	 * @return Long
	 */
	@Override
	public Long getProgramJsonConutByDeviceDownState(Integer state) {
		return programJsonMapper.getProgramJsonConutByDeviceDownState(state);
	}

	/**
	 * 根据下载云端推送广告状态获取广告数量
	 *
	 * @return Long
	 */
	@Override
	public Long getProgramJsonCountByDownloadState(Integer state) {
		return programJsonMapper.getProgramJsonCountByDownloadState(state);
	}

	/**
	 * 获取单个节目详细报表列分页表
	 *
	 * @param receiveStartTime 接收开始时间
	 * @param receiveEndTime   接收结束时间
	 * @param programJsonId    节目主键ID
	 * @param pageNum          当前页
	 * @param pageSize         每页多少条
	 * @return PageInfo<SingleProgramDetailReportVO>
	 */
	@Override
	public PageInfo<SingleProgramDetailReportVO> listSingleProgramDetailReportByPage(String receiveStartTime, String receiveEndTime, Long programJsonId, Integer pageNum, Integer pageSize) {
		if (pageNum == null) {
			pageNum = PageConstant.DEFAULT_PAGE_NUM;
		}
		if (pageSize == null) {
			pageSize = PageConstant.DEFAULT_PAGE_SIZE;
		}
		Long longReceiveStartTime = null;
		Long longReceiveEndTime = null;
		try {
			if (StringUtils.isNotBlank(receiveStartTime)) {
				longReceiveStartTime = DateUtils.stringTimeToLongTimeStamp(receiveStartTime, DateFormatConstant.LONG_DATE_FORMAT_STR);
			}
			if (StringUtils.isNotBlank(receiveEndTime)) {
				longReceiveEndTime = DateUtils.stringTimeToLongTimeStamp(receiveEndTime, DateFormatConstant.LONG_DATE_FORMAT_STR);
			}
		} catch (ParseException e) {
			e.printStackTrace();
		}
		PageHelper.startPage(pageNum, pageSize);
		Page<SingleProgramDetailReportDTO> page = programJsonMapper.listSingleProgramDetailReportByPage(longReceiveStartTime, longReceiveEndTime, programJsonId);
		if (page == null) {
			return new PageInfo<SingleProgramDetailReportVO>(pageNum, pageSize, 0L, null);
		}
		PageInfo pageInfo = new PageInfo<SingleProgramDetailReportVO>();
		pageInfo.setPageNum(pageNum);
		pageInfo.setPageSize(pageSize);
		pageInfo.setTotal(page.getTotal());
		//把long类型时间转化为格式化时间
		List<SingleProgramDetailReportDTO> dtoList = page.getResult();
		List<SingleProgramDetailReportVO> voList = Lists.newArrayList();
		for (SingleProgramDetailReportDTO dto : dtoList) {
			SingleProgramDetailReportVO vo = new SingleProgramDetailReportVO();
			vo.setProgramJsonId(dto.getProgramJsonId());
			vo.setPublishWay(dto.getPublishWay() == null ? "" : "定期发布");
			vo.setRecieveTime(dto.getRecieveTime() == null ? "" : DateUtils.longTimeStampToStringDate(dto.getRecieveTime(), DateFormatConstant.LONG_DATE_FORMAT_STR));
			vo.setDoneTime(dto.getDoneTime() == null ? "" : DateUtils.longTimeStampToStringDate(dto.getDoneTime(), DateFormatConstant.LONG_DATE_FORMAT_STR));
			vo.setMachineNum(dto.getMachineNum());
			vo.setMac(dto.getMac());
			vo.setDeviceProvince(dto.getDeviceProvince());
			vo.setDeviceCity(dto.getDeviceCity());
			vo.setDeviceCounty(dto.getDeviceCounty());
			Integer downloadState = dto.getDownloadState();
			if (BusinessConstant.PROGRAMJSON_STATE_DOWNLOAD_FAIL == downloadState) {
				vo.setDownloadState("下载失败");
			}
			if (BusinessConstant.PROGRAMJSON_STATE_DOWNLOAD_SUCESS == downloadState) {
				vo.setDownloadState("已下载");
			}
			if (BusinessConstant.PROGRAMJSON_STATE_DOWNLOADING == downloadState) {
				vo.setDownloadState("下载中");
			}
			vo.setGroupName(dto.getGroupName());
			voList.add(vo);
		}
		pageInfo.setList(voList);
		return pageInfo;
	}

	/**
	 * 获取导出单个节目详细报表列表
	 *
	 * @param receiveStartTime 接收开始时间
	 * @param receiveEndTime   接收结束时间
	 * @param programJsonId    节目主键ID
	 * @return List<SingleProgramDetailReportData>
	 */
	@Override
	public List<SingleProgramDetailReportData> listExportSingleProgramDetailReport(String receiveStartTime, String receiveEndTime, Long programJsonId) {
		Long exportReceiveStartTime = null;
		Long exportReceiveEndTime = null;
		try {
			if (StringUtils.isNotBlank(receiveStartTime)) {
				exportReceiveStartTime = DateUtils.stringTimeToLongTimeStamp(receiveStartTime, DateFormatConstant.LONG_DATE_FORMAT_STR);
			}
			if (StringUtils.isNotBlank(receiveEndTime)) {
				exportReceiveEndTime = DateUtils.stringTimeToLongTimeStamp(receiveEndTime, DateFormatConstant.LONG_DATE_FORMAT_STR);
			}
		} catch (ParseException e) {
			e.printStackTrace();
		}
		//导出列表
		List<SingleProgramDetailReportData> exportDataList = Lists.newArrayList();
		Page<SingleProgramDetailReportDTO> page = programJsonMapper.listSingleProgramDetailReportByPage(exportReceiveStartTime, exportReceiveEndTime, programJsonId);
		if (page == null) {
			return exportDataList;
		}
		//DTO列表
		List<SingleProgramDetailReportDTO> exportDtoList = page.getResult();
		if (CollectionUtils.isEmpty(exportDtoList)) {
			return exportDataList;
		}
		for (SingleProgramDetailReportDTO dto : exportDtoList) {
			SingleProgramDetailReportData data = new SingleProgramDetailReportData();
			data.setProgramJsonId(dto.getProgramJsonId());
			data.setPublishWay(dto.getPublishWay() == null ? "" : "定期发布");
			data.setRecieveTime(dto.getRecieveTime() == null ? "" : DateUtils.longTimeStampToStringDate(dto.getRecieveTime(), DateFormatConstant.LONG_DATE_FORMAT_STR));
			data.setDoneTime(dto.getDoneTime() == null ? "" : DateUtils.longTimeStampToStringDate(dto.getDoneTime(), DateFormatConstant.LONG_DATE_FORMAT_STR));
			data.setMachineNum(dto.getMachineNum());
			data.setMac(dto.getMac());
			data.setDeviceProvince(dto.getDeviceProvince());
			data.setDeviceCity(dto.getDeviceCity());
			data.setDeviceCounty(dto.getDeviceCounty());
			Integer downloadState = dto.getDownloadState();
			if (BusinessConstant.PROGRAMJSON_STATE_DOWNLOAD_FAIL == downloadState) {
				data.setDownloadState("下载失败");
			}
			if (BusinessConstant.PROGRAMJSON_STATE_DOWNLOAD_SUCESS == downloadState) {
				data.setDownloadState("已下载");
			}
			if (BusinessConstant.PROGRAMJSON_STATE_DOWNLOADING == downloadState) {
				data.setDownloadState("下载中");
			}
			data.setGroupName(dto.getGroupName());
			exportDataList.add(data);
		}
		return exportDataList;
	}

	/**
	 * 获取广告校验失败数
	 *
	 * @return Long
	 */
	@Override
	public Long getProgramJsonAuthFailureCount() {
		return programJsonMapper.getProgramJsonConutByJsonAuth(BusinessConstant.PROGRAMJSON_AUTH_STATE_FAIL);
	}

	/**
	 * 获取广告发布失败数量
	 *
	 * @return Long
	 */
	@Override
	public Long getProgramJsonPublishFailureCount() {
		return programJsonMapper.getProgramJsonConutByDeviceDownState(BusinessConstant.PROGRAMJSON_STATE_DOWNLOAD_FAIL);
	}

	/**
	 * 获取广告总数
	 *
	 * @return Long
	 */
	@Override
	public Long getProgramJsonCount() {
		return programJsonMapper.getProgramJsonCount();
	}

	/**
	 * 获取整体广告分页列表
	 * @param timeType 1:接收时间 2:完成时间
	 * @param startTime 开始时间
	 * @param endTime 结束时间
	 * @param publishWay 发布方式 1：定时发布(当前只有定时发布) 2:预约发布
	 * @param programJsonId 发布Id
	 * @param pageNum 当前页数
	 * @param pageSize 每页条数
	 * @return
	 */
	@Override
	public PageInfo<WholeProgramReportVO> listWholeProgramReportByPage(Integer timeType, String startTime, String endTime, Integer publishWay, Long programJsonId, Integer pageNum, Integer pageSize) {
		pageNum = pageNum == null ? PageConstant.DEFAULT_PAGE_NUM : pageNum;
		pageSize = pageSize == null ? PageConstant.DEFAULT_PAGE_SIZE : pageSize;
		Long longStartTime = null;
		Long longEndTime = null;
		try {
			if(StringUtils.isNotBlank(startTime)) {
				longStartTime = DateUtils.stringTimeToLongTimeStamp(startTime, DateFormatConstant.LONG_DATE_FORMAT_STR);
            }
			if(StringUtils.isNotBlank(endTime)) {
				longEndTime = DateUtils.stringTimeToLongTimeStamp(endTime, DateFormatConstant.LONG_DATE_FORMAT_STR);
            }
		} catch (ParseException e) {
			e.printStackTrace();
		}
		PageHelper.startPage(pageNum, pageSize);
		Page<WholeProgramReportDTO> page = programJsonMapper.listWholeProgramReportByPage(timeType, longStartTime, longEndTime, publishWay, programJsonId);

		if (page == null) {
			return new PageInfo<WholeProgramReportVO>(pageNum, pageSize, 0L, null);
		}

		PageInfo pageInfo = new PageInfo<WholeProgramReportVO>();
		pageInfo.setPageNum(pageNum);
		pageInfo.setPageSize(pageSize);
		pageInfo.setTotal(page.getTotal());
		//把long类型时间转化为格式化时间
		List<WholeProgramReportDTO> dtoList = page.getResult();
		List<WholeProgramReportVO> voList = Lists.newArrayList();
		for (WholeProgramReportDTO dto : dtoList) {
			WholeProgramReportVO vo = new WholeProgramReportVO();
			vo.setProgramJsonId(dto.getProgramJsonId());
			vo.setPublishWay(dto.getPublishWay() == null ? "" : "定期发布");
			vo.setRecieveTime(dto.getReceiveTime() == null ? "" : DateUtils.longTimeStampToStringDate(dto.getReceiveTime(), DateFormatConstant.LONG_DATE_FORMAT_STR));
			vo.setDoneTime(dto.getDoneTime() == null ? "" : DateUtils.longTimeStampToStringDate(dto.getDoneTime(), DateFormatConstant.LONG_DATE_FORMAT_STR));
			vo.setDeviceNum(dto.getDeviceNum());
			voList.add(vo);
		}
		pageInfo.setList(voList);
		return pageInfo;
	}

	/**
	 * 获取节目相关统计信息
	 */
	@Override
	public ProgramJsonStatVO getProgramJsonStat() {
		return programJsonMapper.getProgramJsonStat();
	}

}
